#ifndef __CURVE__
#define __CURVE__

#include "primitive.h"
#include "dispatcher.h"

struct DerivativesDim1 : public Derivatives {
	DerivativesDim1(size_t d);
	boost::multi_array<Vec3n, 1> D;
	boost::multi_array<Vec4n, 1> Dw;
	size_t d;
};

class Curve : public Primitive {
public:
	Curve(const std::vector<Vec4n>& Pw, size_t p, const Knotvector& U);
	Curve(const std::vector<Vec3n>& Pw, size_t p, const Knotvector& U);
	Curve(const Curve& curve);
	Curve() {}

	void Derivative(nfloat* param, Derivatives* pd) const;
	Vec3n Evaluate(const boost::array<nfloat, 1>& param) const;
	Vec3n Evaluate(nfloat t) const;
	Matrix TBN(const nfloat t) const;
	virtual void Refine();
	virtual void Refine(const std::vector<Knotvector>& X);
	void Refine(nfloat t);
	bool Remove(nfloat u, size_t num);
	nfloat Curvature(nfloat u) const;

	void DegreeElevate(int t);
	
	virtual void Save(const std::string& filename, const std::string& attribute);
	
	size_t GetDegree() const {return p;}
	const Knotvector& GetKnotvector() const {return U;}

	size_t Size() const {return Pw.size();}
	Vec4n& operator()(int i) {
		if(i < 0) i = Pw.size() + i;
		return Pw[i];
	}

	const Vec4n& operator()(int i) const {
		if(i < 0) i = Pw.size() - i;
		return Pw[i];
	}

	virtual void Dispatch(Dispatcher* d) {
		d->Visit(this);
	}
private:
	void Save(const std::string& filename);
	void RefineKnotVectCurve(size_t n, size_t p, const Knotvector& U, const std::vector<Vec4n>& Pw, const Knotvector& X, size_t r, Knotvector& Ubar, std::vector<Vec4n>& Qw);
	size_t RemoveCurveKnot(size_t n, size_t p, Knotvector& U, std::vector<Vec4n>& Pw, nfloat u, size_t r, size_t s, size_t num, size_t& t);

	void binomialCoef(Matrix& Bin) const;

	std::vector<Vec4n> Pw;
	size_t p;
	// n is the # of control points - 1
	size_t n;
	Knotvector U;
};
	
#endif //__SURFACE__
